package jia.editor;

import jia.game.GenericFlags;
import jia.core.GameStateManager;
import jia.core.Compass;
import org.apache.log4j.Logger;

import javax.swing.*;
import javax.vecmath.Vector2d;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * @author Alec Lanter
 */
public class ModuleEditorPanel extends JPanel implements EditorViewport, ActionListener{
    private static final Logger log = Logger.getLogger(ModuleEditorPanel.class);
    private JScrollPane scroller;
    private ModuleEditorViewport viewport;
    private GameStateManager gameState;
    private ModuleEditorPanelController controller;
    private static final String CMD_ZOOMIN = "zoomin";
    private static final String CMD_ZOOMOUT = "zoomout";
    
    /**
     */
    public ModuleEditorPanel(){
        initComponents();
    }
    
    /**
     */
    private void initComponents(){
        setFocusable(false);
        viewport = new ModuleEditorViewport();
        scroller = new JScrollPane(viewport);
        setLayout(new BorderLayout());
        add(scroller, BorderLayout.CENTER);
        controller = new ModuleEditorPanelController(this);
        scroller.addMouseListener(new ModuleEditorPanelMouseListener(controller));
        scroller.addMouseMotionListener(new ModuleEditorPanelMouseMotionListener(controller));
        scroller.setFocusable(false);
        viewport.setFocusable(false);
        setSize(200, 200);
        setMinimumSize(getSize());
        JPanel buttons = new JPanel();
        JButton btnZoomIn = new JButton("Zoom +");
        JButton btnZoomOut = new JButton("Zoom -");
        btnZoomIn.setActionCommand(CMD_ZOOMIN);
        btnZoomOut.setActionCommand(CMD_ZOOMOUT);
        btnZoomIn.addActionListener(this);
        btnZoomOut.addActionListener(this);
        buttons.add(btnZoomIn);
        buttons.add(btnZoomOut);
        add(buttons, BorderLayout.SOUTH);
    }
    
    /**
     * @see net.sf.jia.ui.AbstractViewport#updateGameState(net.sf.jia.core.GameStateManager)
     */
    public void updateGameState(GameStateManager gameState){
        this.gameState = gameState;
        viewport.updateGameState(gameState);
    }
    
    /**
     * @see net.sf.jia.editor.ui.EditorViewport#getGridWidth()
     */
    public int getGridWidth(){
        return viewport.getGridWidth();
    }
    
    /**
     * @see net.sf.jia.editor.ui.EditorViewport#getGridHeight()
     */
    public int getGridHeight(){
        return viewport.getGridHeight();
    }
    
    /**
     * @see net.sf.jia.editor.ui.EditorViewport#setGridWidth(int)
     */
    public void setGridWidth(int width){
        viewport.setGridWidth(width);
    }
    
    /**
     * @see net.sf.jia.editor.ui.EditorViewport#setGridHeight(int)
     */
    public void setGridHeight(int height){
        viewport.setGridHeight(height);
    }
    
    /**
     * @see net.sf.jia.editor.ui.EditorViewport#getScreenData(int,int)
     */
    public ScreenLocationData getScreenData(int mouseX, int mouseY){
        mouseX += scroller.getViewport().getViewPosition().x;
        mouseY += scroller.getViewport().getViewPosition().y;
        if(GenericFlags.debugMessages) {
            log.debug("Actual mouse values are " + mouseX + ", " + mouseY);
        }
        ScreenLocationData data = new ScreenLocationData();
        
        // Determine which space was clicked
        double posX = (double) mouseX / (double) viewport.getGridWidth();
        double posY = (double) mouseY / (double) viewport.getGridHeight();
        data.setModuleLoc(new Vector2d((int) posX, (int) posY));
        
        // Now determine which wall we clicked closest on
        int gridWidth = viewport.getGridWidth();
        int gridHeight = viewport.getGridHeight();
        int inSquareX = mouseX % gridWidth;
        int inSquareY = mouseY % gridHeight;
        
        // If we clicked on a grid junction, we didn't click on a wall
        if((inSquareX < 4 || inSquareX > gridWidth - 4) && (inSquareY < 4 || inSquareY > gridHeight - 4)) {
            data.setClosestWall(null);
        } else if(inSquareX > gridWidth - 4) {
            data.setClosestWall(Compass.EAST);
        } else if(inSquareX < 4) {
            data.setClosestWall(Compass.WEST);
        } else if(inSquareY > gridHeight - 4) {
            data.setClosestWall(Compass.SOUTH);
        } else if(inSquareY < 4) {
            data.setClosestWall(Compass.NORTH);
        }
        // And if we didn't click on a wall, we...uhm...didn't click on a wall.
        else {
            data.setClosestWall(null);
        }
        if(GenericFlags.debugMessages) {
            log.debug("You clicked on grid " + data.getModuleLoc().x + ", " + data.getModuleLoc().y);
        }
        if(data.getClosestWall() != null) {
            if(GenericFlags.debugMessages) {
                log.debug("The closest wall is " + data.getClosestWall().getCardinalName());
            }
        } else {
            if(GenericFlags.debugMessages) {
                log.debug("You didn't click on a wall.");
            }
        }
        return data;
    }
    
    /**
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */
    public void actionPerformed(ActionEvent arg0){
        String cmd = arg0.getActionCommand();
        if(CMD_ZOOMIN.equals(cmd)) {
            if(viewport.getGridWidth() < 64) {
                viewport.setGridWidth(viewport.getGridWidth() * 2);
                viewport.setGridHeight(viewport.getGridWidth());
            }
            scroller.setViewportView(viewport);
        } else if(CMD_ZOOMOUT.equals(cmd)) {
            if(viewport.getGridWidth() > 8) {
                viewport.setGridWidth(viewport.getGridWidth() / 2);
                viewport.setGridHeight(viewport.getGridWidth());
            }
            scroller.setViewportView(viewport);
        }
    }
    
    /**
     * @return Returns the controller.
     */
    public ModuleEditorPanelController getController(){
        return controller;
    }
    
    /**
     * @return Returns the gsm.
     */
    protected GameStateManager getGameState(){
        return gameState;
    }
    
    /**
     * @param gsm The gsm to set.
     */
    protected void setGameState(GameStateManager gsm){
        this.gameState = gsm;
    }
}
